import { ComponentPublicInstance, h } from 'vue'
import UnHandlerErrorContent, {
  ErrorInfoType,
} from 'components/UnHandlerErrorContent.vue'

import ResourceLoadErrorContent, {
  ResourceErrorInfoType,
} from 'components/ResourceLoadErrorContent.vue'

window.onerror = (msg, url, lineNum, colNum, err) => {
  console.log(`错误发生的异常信息（字符串）:${msg}`)
  console.log(`错误发生的脚本URL（字符串）:${url}`)
  console.log(`错误发生的行号/列号（数字）:${lineNum}/${colNum}`)
  console.log(`错误发生的Error对象（错误对象）:${err}`)
}

window.addEventListener('unhandledrejection', e => {
  console.log(`Promise.reject()中的内容，告诉你发生错误的原因:${e.reason}`)
  console.log(`Promise对象 :${e.promise}`)
})

window.addEventListener(
  'error',
  errorEvent => {
    if (!errorEvent.message) {
      // @ts-ignore
      const tagName = errorEvent.target.tagName
      // @ts-ignore
      const srcVal = errorEvent.target.getAttribute('src')
      // @ts-ignore
      const linkVal = errorEvent.target.getAttribute('link')
      // @ts-ignore
      const altVal = errorEvent.target.getAttribute('alt')
      const errorInfo: ResourceErrorInfoType = {
        tagName,
        src: srcVal,
        link: linkVal,
        alt: altVal,
      }
      console.error(errorEvent)
      ElNotification({
        title: '资源加载失败',
        message: h(ResourceLoadErrorContent, { errorInfo }),
        type: 'error',
        duration: 0,
        position: 'bottom-right',
      })
    }
  },
  true
)

function extractErrorInfo(error: Error, vueInfo?: string): ErrorInfoType {
  let stack = error.stack
  if (stack) {
    const stackArr = stack.split('\n')
    stack = ''
    const maxIdx = 2
    for (let i = 0; i < stackArr.length; i++) {
      stack += stackArr[i]
      if (i >= maxIdx) {
        break
      } else {
        stack += '\n'
      }
    }
  }
  return {
    name: error.name,
    message: error.message,
    stack,
    vueInfo,
  }
}

function extractErrorInfoFromUnknown(
  error: unknown,
  vueInfo?: string
): ErrorInfoType {
  return {
    name: '未知错误',
    message: error as string,
    stack: '',
    vueInfo,
  }
}

/**
 * vue全局异常处理
 * @param err
 * @param instance
 * @param info
 */
export function globalErrorHandler(
  err: unknown,
  instance: ComponentPublicInstance | null,
  info: string
) {
  console.error(err)
  if (err instanceof Error) {
    const errorInfo = extractErrorInfo(err, info)
    ElNotification({
      title: '前端未处理错误',
      message: h(UnHandlerErrorContent, { errorInfo }),
      type: 'error',
      duration: 0,
      position: 'bottom-right',
    })
  } else {
    const errorInfo = extractErrorInfoFromUnknown(err, info)
    ElNotification({
      title: '前端未处理错误',
      message: h(UnHandlerErrorContent, { errorInfo }),
      type: 'error',
      duration: 0,
      position: 'bottom-right',
    })
  }
}
